#ifndef MENUEVENTS_HPP
#define MENUEVENTS_HPP

#include <boost/any.hpp>
#include <boost/signals.hpp>
#include <string>
#include <vector>
#include <FL/Fl_Widget.H>
#include "FlEx.hpp"
class Panel;
namespace boost
{
   typedef std::vector<boost::any> many;
}
typedef boost::signal<void (boost::many&)> MenuSignal;

template <typename C>
struct ToggleVisibleFn
{
   ToggleVisibleFn(C* aWidget) : mWidget(aWidget) {}
   void operator()(boost::many& args)
   {
      if (! mWidget->visible())
      {
         mWidget->show();
         FlEx::MakeTopmost(mWidget);
      } else
      {
         mWidget->hide();
      }      
   }
   C* mWidget;
};
// Handles user interface events
class MenuEvents
{
public:  
   MenuEvents();
   void operator()(std::string aCommand)
   {
      boost::many args;
      Handle(aCommand, args);
   }
   void operator()(std::string       aCommand,
                   const boost::any& arg1)
   {
      boost::many args;
      args.push_back(arg1);
      Handle(aCommand, args);
   }
   void operator()(std::string       aCommand,
                   const boost::any& arg1,
                   const boost::any& arg2)
   {
      boost::many args;
      args.push_back(arg1);
      args.push_back(arg2);
      Handle(aCommand, args);
   }
   void operator()(std::string       aCommand,
                   const boost::any& arg1,
                   const boost::any& arg2,
                   const boost::any& arg3)
   {
      boost::many args;
      args.push_back(arg1);
      args.push_back(arg2);
      args.push_back(arg3);
      Handle(aCommand, args);
   }
   void operator()(std::string       aCommand,
                   const boost::any& arg1,
                   const boost::any& arg2,
                   const boost::any& arg3,
                   const boost::any& arg4)
   {
      boost::many args;
      args.push_back(arg1);
      args.push_back(arg2);
      args.push_back(arg3);
      args.push_back(arg4);
      Handle(aCommand, args);
   }
   // Execute a command with 'args'
   // Unprocessed commands are forwarded using boost::signals
   void Handle(std::string        aCommand,
               boost::many& aArgs);

   // Returns a signal for the command (use connect() to handle the command)
   MenuSignal& Signal(const std::string& aCommand);

private:

   void LoadMeshConfig();
   void PullMeshConfig();

   bool DoSignals(std::string  aCommand,
                  boost::many& aArgs);
   typedef std::map<std::string, MenuSignal*> SignalMap;
   SignalMap mSignals;

   Panel* mPanel;   
};


extern MenuEvents MEvents;

#endif